import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
  Logger,
  HttpStatus,
  PayloadTooLargeException,
} from "@nestjs/common";
import { Request, Response } from "express";
import { MulterError } from "multer";

@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
  // exception 当前正在处理的异常对象
  // host 是传递给原始处理程序的参数的一个包装(Response/Request)的引用
  catch(exception: HttpException, host: ArgumentsHost) {
    console.log("进入全局异常过滤器...");
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    // HttpException 属于基础异常类，可自定义内容
    // 如果是自定义的异常类则抛出自定义的status
    // 否则就是内置HTTP异常类，然后抛出其对应的内置Status内容
    let status =
      exception instanceof HttpException
        ? exception.getStatus()
        : HttpStatus.INTERNAL_SERVER_ERROR;

    let errors = null;
    let formattedErrors = "";
    // 为了取管道异常
    if (exception instanceof HttpException) {
      // 抛出错误信息
      errors = exception.getResponse() as any[];
      if (errors["message"] && Array.isArray(errors["message"])) {
        // 管道认证抛出的异常
        formattedErrors = errors["message"].join(",");
      }
    }
    let message = formattedErrors || exception.message || "错误";

    // 处理文件上传异常
    if (message === "File too large") {
      // 文件大小超过限制的错误处理
      status = HttpStatus.PAYLOAD_TOO_LARGE;
      message = "文件大小超过限制";
    }

    console.log(exception instanceof Error, exception, "exception 2");

    // 处理其他错误集合
    if (exception instanceof Error) {
      status = (exception as any).status;

      console.log(exception as any, "(exception as any)");
      console.log((exception as any).code, "(exception as any).code");
      console.log(status, "status");

      // 链接数据库超时
      if ((exception as any).code === "ETIMEDOUT") {
        message = "链接超时！";
      }
      // 文件错误类型
      if ((exception as any).code === "ENOENT") {
        // 处理静态文件资源
        message = "文件路径有误";
      }
      // json 入参错误
      if (status === 400 && exception.message.includes("Unexpected token")) {
        message = `Invalid JSON input: ${exception.message.split("at position ")[1]}`;
      }
    }

    const msgLog = {
      success: false, // 请求是否成功
      statusCode: status || HttpStatus.INTERNAL_SERVER_ERROR, // 系统错误状态
      timestamp: new Date().toISOString(), // 错误日期
      path: request.url, // 错误路由
      errMsg: message || "请求失败",
      data: [], // 错误消息内容体(争取和拦截器中定义的响应体一样)
    };
    // 打印错误综合日志
    Logger.error("错误信息", JSON.stringify(msgLog), "HttpExceptionFilter");
    response.status(status || HttpStatus.INTERNAL_SERVER_ERROR).json(msgLog);
  }
}
